package com.store.orm.mongo.curd.impl;

import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.store.orm.mongo.curd.MongoUtil;
import com.store.orm.mongo.curd.Select;
import com.store.orm.util.JsonUtil;
import org.bson.Document;
import org.bson.conversions.Bson;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;

import static com.mongodb.client.model.Filters.and;
import static com.mongodb.client.model.Filters.eq;

/**
 * @author 宫静雨
 * @version 1.0
 */
@SuppressWarnings("all")
public class MongoSelect implements Select {
    private MongoDatabase database;
    private static final MongoUtil util = new MongoUtil();

    public MongoSelect(MongoDatabase database) {
        this.database = database;
    }

    private FindIterable<Document> helpT(MongoCollection<Document> collection, LinkedHashMap<String, Object> map) {
        if (map.size() == 0) {
            return collection.find();
        }
        if (map.containsKey("id")) {
            Object id = map.get("id");
            map.remove("id");
            map.put("_id", id);
        }
        LinkedHashMap<String, Object> cascade = util.cascade(map);
        List<Bson> bsons = new ArrayList<>();
        cascade.forEach((k, v) -> bsons.add(eq(k, v)));
        Bson and = and(bsons);
        return collection.find(and);
    }

    private <T> List<T> getItems(FindIterable<Document> documents, Class<T> cls) {
        List<T> res = new ArrayList<>();
        for (Document document : documents) {
            res.add(util.parseDocToPojo(document, cls));
        }
        return res;
    }

    @Override
    public <T> List<T> find(T t) {
        Class<T> cls = (Class<T>) t.getClass();
        MongoCollection<Document> collection = database.getCollection(util.collection(cls));
        LinkedHashMap<String, Object> map;
        try {
            map = util.parseTToMap(t);
        } catch (Exception e) {
            throw new RuntimeException();
        }
        FindIterable<Document> documents = helpT(collection, map);
        return getItems(documents, cls);
    }

    @Override
    public <T> List<T> find(Class<T> cls, String json) {
        MongoCollection<Document> collection = database.getCollection(util.collection(cls));
        LinkedHashMap<String, Object> map = JsonUtil.parse(json);
        FindIterable<Document> documents = helpT(collection, map);
        return getItems(documents, cls);
    }

    @Override
    public <T> List<T> find(Class<T> cls, LinkedHashMap<String, Object> map) {
        MongoCollection<Document> collection = database.getCollection(util.collection(cls));
        FindIterable<Document> documents = helpT(collection, map);
        return getItems(documents, cls);
    }

    @Override
    public <T> List<T> find(Class<T> cls, Bson filter) {
        MongoCollection<Document> collection = database.getCollection(util.collection(cls));
        FindIterable<Document> documents = collection.find(filter);
        return getItems(documents, cls);
    }
}